package com.colourclash.fruitopia.controllers 
{
	import com.colourclash.fruitopia.enums.FruitType;
	import com.colourclash.fruitopia.models.FruitModel;
	import com.colourclash.fruitopia.models.FruitopiaGameModel;
	import com.colourclash.fruitopia.resources.EmbeddedAssets;
	import com.colourclash.fruitopia.utils.BaseController;
	import com.greensock.TweenLite;
	import flash.display.Sprite;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	/**
	 * This class has public methods called by the FruitopiaGameView
	 * In turn, it modifies the FruitopiaGameModel
	 * @author Patrick Hammond
	 */
	public class FruitopiaGameController extends BaseController
	{
		private var _model:FruitopiaGameModel;
		
		//flag to indicate the necessity to reverse the previous swap
		private var _swapBackAfterNonMatch:Boolean;
		
		private var _musicChannel:SoundChannel;

		public function FruitopiaGameController(model:FruitopiaGameModel) 
		{
			super(model);
			
			_model = model;
		}
		
		override public function initialise():void 
		{
			//create the initial fruits
			_model.createFruits();
			
			//loop some music
			_musicChannel = (new EmbeddedAssets.Tune() as Sound).play(0, 9999);
			
			//increase the difficulty every 2 minutes
			TweenLite.delayedCall(120, increaseLevel);
		}

		public function selectFirstFruit(model:FruitModel):void 
		{
			_model.firstSelectedFruit = model;
		}
		
		public function selectSecondFruit(model:FruitModel):void 
		{
			if (_model.firstSelectedFruit != null)
				_model.secondSelectedFruit = model;
			
			swapFruits();
		}
		
		public function turnComplete():void 
		{
			if (_swapBackAfterNonMatch)
			{
				swapFruits();
			}
			else
			{
				checkForMatch();
			}
		}
		
		public function destroyAllFruit():void 
		{
			for (var i:int = 0; i < 5; i++) 
				for (var j:int = 0; j < 5; j++) 
					(_model.fruits[i][j] as FruitModel).isDestroyed = true;
					
			_model.updateFruits();
		}
		
		public function increaseLevel():void 
		{
			if (_model.numberOfFruits < 7)
			{
				_model.numberOfFruits++;
				TweenLite.delayedCall(120, increaseLevel);
			}
		}
		
		//given a destroyed fruit, returns a new random type of fruit
		public function getNewFruit(fruit:FruitModel):FruitModel
		{
			fruit.isDestroyed = false;
			fruit.type = FruitType.getTypeByIndex(int(Math.random() * _model.numberOfFruits));
			return fruit;
		}
		
		public function increaseScore(points:int):void
		{
			_model.score += points;
		}
		
		//looks at the whole grid for any consecutive sequences of 3 fruit 
		private function checkForMatch(onlyTest:Boolean = false):Boolean 
		{
			var matchCount:int = 0;
			
			for (var i:int = 0; i < 5; i++) 
			{
				for (var j:int = 0; j < 5; j++) 
				{
					var fruit:FruitModel = _model.fruits[i][j] as FruitModel;
					
					var hMatches:Array = checkSequenceOfThree(i, j);
					var vMatches:Array = checkSequenceOfThree(i, j, true);
					
					if (!onlyTest)
					{
						for each (var hMatch:FruitModel in hMatches) 
							hMatch.isDestroyed = true;
						
						for each (var vMatch:FruitModel in vMatches) 
							vMatch.isDestroyed = true;
					}
					
					matchCount += hMatches.length + vMatches.length;
				}
			}
			
			if (!onlyTest)
			{
				increaseScore(matchCount * 400);
				
				if (matchCount > 0)
					decendFruits();
			}
					
			return matchCount > 0;
		}
		
		private function checkSequenceOfThree(row:int, column:int, checkVertically:Boolean = false):Array 
		{
			var comparisonFruit:FruitModel = _model.fruits[row][column];
			var matches:Array = [comparisonFruit];
			
			var count:int = checkVertically ? row + 1 : column + 1;
			
			while (count < 5)
			{
				var fruit:FruitModel = checkVertically ? 
						_model.fruits[count][column] as FruitModel :
						_model.fruits[row][count] as FruitModel;
						
				if (fruit.type == comparisonFruit.type)
					matches.push(fruit);
				else
					break;
			
				count++;
			}
			
			if (matches.length < 3)
				return [];
				
			return matches;
		}
		
		//swaps two adjacent pieces of fruit
		private function swapFruits():void 
		{
			if (isValidSwap())
			{
				_model.fruits[_model.firstSelectedFruit.row][_model.firstSelectedFruit.column] = _model.secondSelectedFruit;
				_model.fruits[_model.secondSelectedFruit.row][_model.secondSelectedFruit.column] = _model.firstSelectedFruit;
				
				var temp:Object = { row:_model.firstSelectedFruit.row, column:_model.firstSelectedFruit.column };
				_model.firstSelectedFruit.row = _model.secondSelectedFruit.row;
				_model.firstSelectedFruit.column = _model.secondSelectedFruit.column;
				_model.secondSelectedFruit.row = temp.row;
				_model.secondSelectedFruit.column = temp.column;

				if (_swapBackAfterNonMatch == true)
					_swapBackAfterNonMatch = false;
				else if (checkForMatch(true) == false)
					_swapBackAfterNonMatch = true;
				
				_model.updateFruits();
			}
		}
		
		private function isValidSwap():Boolean 
		{
			if (_model.firstSelectedFruit.row 	 != _model.secondSelectedFruit.row &&
				_model.firstSelectedFruit.column != _model.secondSelectedFruit.column)
				return false;
			
			if (_model.firstSelectedFruit.row 	 - _model.secondSelectedFruit.row > 1 ||
				_model.firstSelectedFruit.column - _model.secondSelectedFruit.column > 1)
				return false;
				
			return true;
		}
		
		//drop the non-destroyed fruit pieces to the bottom of the grid
		private function decendFruits():void 
		{
			for (var j:int = 0; j < 5; j++) 
			{
				var reorderedColumn:Array = [];
				var fruit:FruitModel;
				for (var i:int = 0; i < 5; i++) 
				{
					fruit = _model.fruits[i][j];
					if (fruit.isDestroyed)
						reorderedColumn.push(fruit);
				}
				for (var k:int = 0; k < 5; k++) 
				{
					fruit = _model.fruits[k][j];
					if (!fruit.isDestroyed)
						reorderedColumn.push(fruit);
				}
				for (var l:int = 0; l < 5; l++) 
				{
					fruit = reorderedColumn[l];
					fruit.row = l;
					_model.fruits[l][j] = fruit;
				}
			}
			
			_model.updateFruits();
		}
	}

}